/*******************************************************************************
 * Copyright (c) 2010 European Software Institute - Tecnalia.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Author - Adri�n Noguero (adrian.noguero@esi.es)
 *     
 *******************************************************************************/
package es.esi.gemde.modelvalidator.ui.wizards;

import java.util.List;
import java.util.Vector;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;

import es.esi.gemde.core.CorePlugin;
import es.esi.gemde.core.resources.IGemdeResource.ResourceType;
import es.esi.gemde.modelvalidator.ModelValidatorPlugin;
import es.esi.gemde.modelvalidator.service.BatchValidationFactory;
import es.esi.gemde.modelvalidator.service.IBatchValidation;
import es.esi.gemde.modelvalidator.service.IModelValidatorConstraint;

/**
 * A wizard for creating batch validations
 *
 * @author Adrian Noguero (adrian.noguero@tecnalia.com)
 * @version 1.0.4
 * @since 1.0
 *
 */
public class ValidationCreationWizard extends Wizard {
	
	private boolean canFinish = false;
	private String name;
	private List<IModelValidatorConstraint> selectedConstraints;
	private IBatchValidation createdValidation;
	
	/**
	 * Initializes the wizard with default values.
	 *
	 */
	public ValidationCreationWizard() {
		super();
		setWindowTitle("Create a new Validation");
		name = null;
		selectedConstraints = new Vector<IModelValidatorConstraint>();
	}
	
	/**
	 * Initializes the wizard with a validation.
	 *
	 *@param name the name of the loaded validation
	 *@param selectedConstraints the constraints selected in this validation
	 */
	public ValidationCreationWizard(String name, List<IModelValidatorConstraint> selectedConstraints) {
		super();
		setWindowTitle("Create a new Validation");
		this.name = name;
		this.selectedConstraints = selectedConstraints;
	}
	
	/**
	 * Returns the created {@link IBatchValidation} instance.
	 * 
	 * @return the instance
	 */
	public IBatchValidation getCreatedValidation () {
		return createdValidation;
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.jface.wizard.Wizard#performFinish()
	 */
	@Override
	public boolean performFinish() {
		createdValidation = BatchValidationFactory.createBatchValidation(name, selectedConstraints, selectedConstraints.get(0).getApplicationMetamodel());
		return true;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.jface.wizard.Wizard#addPages()
	 */
	@Override
	public void addPages() {
		addPage(new NewValidationPage());
	}

	/* (non-Javadoc)
	 * @see org.eclipse.jface.wizard.Wizard#canFinish()
	 */
	@Override
	public boolean canFinish() {
		return canFinish;
	}
	
	/**
	 * The implementation of the only page of this wizard
	 *
	 * @author Adri�n Noguero (adrian.noguero@esi.es)
	 * @version 1.0
	 * @since 1.0
	 *
	 */
	private class NewValidationPage extends WizardPage {
		
		private static final String NAME = "Edit Validation Page";
		
		private Text nameText;
		private CheckboxTreeViewer constraintSelector;
		private Label helpLabel;
		
		/**
		 * Default Constructor. Calls the constructor of the super-class.
		 *
		 */
		private NewValidationPage() {
			super(NAME, "Create a Validation", null);
		}
		
		/**
		 * Internal method that initializes the data in the constraint selector viewer.
		 */
		private void createTree() {
			Tree data = constraintSelector.getTree();
			data.removeAll();
			List<String> categories = ModelValidatorPlugin.getServer().getConstraintCategories();
			List<IModelValidatorConstraint> constraints = ModelValidatorPlugin.getServer().getConstraintRepository();
			for (String category : categories) {
				TreeItem catItem = new TreeItem(data, SWT.NONE);
				catItem.setText(category);
				catItem.setImage(CorePlugin.getImageDescriptor(CorePlugin.CATEGORY_ICON).createImage());
				catItem.setData(category);
				for (IModelValidatorConstraint constraint : constraints) {
					// Show only NORMAL constraints!!
					if (constraint.getResourceType().equals(ResourceType.NORMAL)) {
						if (category.equals(constraint.getCategory())) {
							TreeItem constItem = new TreeItem(catItem, SWT.NONE);
							constItem.setText(constraint.getName());
							switch (constraint.getSeverity()) {
							case IStatus.INFO:
								constItem.setImage(CorePlugin.getImage(CorePlugin.CONSTRAINT_ICON, CorePlugin.INFO_OVERLAY, CorePlugin.TOP_LEFT));
								break;
							case IStatus.WARNING:
								constItem.setImage(CorePlugin.getImage(CorePlugin.CONSTRAINT_ICON, CorePlugin.WARNING_OVERLAY, CorePlugin.TOP_LEFT));
								break;
							case IStatus.ERROR:
								constItem.setImage(CorePlugin.getImage(CorePlugin.CONSTRAINT_ICON, CorePlugin.ERROR_OVERLAY, CorePlugin.TOP_LEFT));
								break;
							default:
								constItem.setImage(CorePlugin.getImage(CorePlugin.CONSTRAINT_ICON));
								break;
							}
							constItem.setData(constraint);
						}
					}
				}
			}
			
			// Now set the checkboxes if required
			if (selectedConstraints.size() > 0) {
				constraintSelector.setCheckedElements(selectedConstraints.toArray());
			}
		}

		/* (non-Javadoc)
		 * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
		 */
		@Override
		public void createControl(Composite parent) {
			Composite topPanel = new Composite(parent, SWT.NONE);
			topPanel.setLayout(new GridLayout(6, true));
			
			topPanel.setSize(400, 600);
			
			// Creating controls in order!
			
			Label nameLabel = new Label(topPanel, SWT.NONE);
			GridData nameLabelData = new GridData();
			nameLabelData.horizontalSpan = 1;
			nameLabel.setText("Validation Name:");
			nameLabel.setLayoutData(nameLabelData);
			
			nameText = new Text(topPanel, SWT.BORDER | SWT.LEFT);
			GridData nameTextData = new GridData(GridData.FILL_HORIZONTAL);
			nameTextData.horizontalSpan = 5;
			nameText.setLayoutData(nameTextData);
			if (name == null || name.equals("")) {
				nameText.setText("");
			}
			else {
				nameText.setText(name);
				nameText.setEditable(false);
			}
			
			constraintSelector = new CheckboxTreeViewer(topPanel, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
			GridData constraintSelectorData = new GridData(GridData.FILL_BOTH);
			constraintSelectorData.horizontalSpan = 6;
			constraintSelector.getTree().setLayoutData(constraintSelectorData);
			
			createTree(); // Fill the tree with the constraint repository data
			
			helpLabel = new Label(topPanel, SWT.NONE);
			GridData helpLabelData = new GridData(GridData.FILL_HORIZONTAL);
			helpLabelData.horizontalSpan = 6;
			helpLabel.setText("");
			helpLabel.setLayoutData(helpLabelData);
			
			
			
			// Add Listeners
			nameText.addModifyListener(nameListener);
			constraintSelector.addCheckStateListener(checkListener);
			
			// Add explanation text
			if (name == null || name.equals("")) {
				setTitle("Create a new Validation");
			}
			else {
				setTitle("Edit a Validation");
			}
			setDescription("Give a name of the validation and select the constraints that will be included in it.");
			
			// Set the control!!
			setControl(topPanel);
		}
		
		private ModifyListener nameListener = new ModifyListener () {

			@Override
			public void modifyText(ModifyEvent e) {
				updateFinish();
			}
			
		};
		
		private ICheckStateListener checkListener = new ICheckStateListener() {

			@Override
			public void checkStateChanged(CheckStateChangedEvent event) {
				// If a category changes
				if (event.getElement() instanceof String) {
					// Find the category item and change the status of the classes.
					TreeItem [] items = constraintSelector.getTree().getItems();
					boolean found = false;
					int i = 0;
					while (!found) {
						if (event.getElement().equals(items[i].getData())) {
							found = true;
						}
						else {
							i++;
						}
					}
					for (TreeItem child : items[i].getItems()) {
						child.setChecked(event.getChecked());
					}
				}
				updateFinish();
			}
			
		};
		
		/**
		 * Internal method called after a listener has been triggered
		 */
		private void updateFinish () {
			name = nameText.getText();
			selectedConstraints.clear();
			for (Object current : constraintSelector.getCheckedElements()) {
				if (current instanceof IModelValidatorConstraint) {
					selectedConstraints.add((IModelValidatorConstraint) current);
				}
			}
			
			boolean differentMM = false;
			EPackage metamodel = null;
			for (IModelValidatorConstraint current : selectedConstraints) {
				if (metamodel == null) {
					metamodel = current.getApplicationMetamodel();
				}
				else {
					if (!metamodel.equals(current.getApplicationMetamodel())) {
						differentMM = true;
					}
				}
			}
			
			if (name != null && !name.equals("") && !selectedConstraints.isEmpty() && !differentMM) {
				canFinish = true;
				helpLabel.setText("");
			}
			else {
				canFinish = false;
				if (differentMM) {
					helpLabel.setText("All selected constraints must refer to the same metamodel.");
				}
				else {
					helpLabel.setText("");
				}
			}
			setPageComplete(true);
		}
	}
	

}
